package hyl.base.net.bio;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;

import hyl.base.kv.cache.QueueObject;
import hyl.base.net.IData1;
import hyl.base.net.IpgReader;
import hyl.core.run.IDo1;
import hyl.core.run.MyRun;

// 我们假设TCP数据包的结构 包长度+包体 
//包长度 = 包体长度,包长度本身是4个字节 可以转换为int类型
//把读到的数据转成 DataPack
/**
 * BIOReader 实例化目的 为了接收 socket 中的数据 <br>
 * 
 * bind socket 以后 我们可以进行双工通信
 * 
 * 并且解决了分包和粘包的问题
 * 
 * 数据接收后 转交给 上层函数处理
 * 
 * @author 37798955@qq.com
 *
 */
public class BIOReader implements IpgReader, Runnable {

	// client 的 BIOSocket._client==_当前连接
	Socket _当前连接;
	private QueueObject<BIOData1> _q待处理队列;
	BIOSocketSrv _srv;
	InputStream _reader = null;
	OutputStream _writer = null;

	// String[] _服务项目;

	IDo1<IpgReader> _收到处理函数 = null;

	// 适用于客户端
	public BIOReader(Socket socket) {

		_q待处理队列 = new QueueObject<BIOData1>("./net/", null, 0);
		this._当前连接 = socket;
		try {
			_reader = socket.getInputStream();
			_writer = socket.getOutputStream();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	Thread curThread = null;

	// 主要适用于服务端,客户端也能用
	public BIOReader(Socket socket, IDo1<IpgReader> 收到处理函数) {
		this(socket);
		if (收到处理函数 != null) {
			this._收到处理函数 = 收到处理函数;
			// 如果有接收代理函数 就启动一个独立线程负责接收后的工作
			// 工作内容主要就是从带处理队列中取出没有处理的数据包进行处理,需要直接写
			curThread = MyRun.start用户线程(() -> _收到处理函数.run(this));
			

		}
	}

	// 主要适用于服务端,客户端也能用
	public BIOReader(BIOSocketSrv sk, Socket socket, IDo1<IpgReader> 收到处理函数) {
		this(socket, 收到处理函数);
		_srv = sk;

	}

	BIOData1 _当前内容 = new BIOData1();
	public boolean isConnected() {
		return _当前连接.isConnected();
	}
	@Override
	// 把数据包从流中 取出,并打包好放入待处理队列
	public void run() {
		try {
			while (!_当前连接.isClosed()) {
				// 防止丢包 分包,取完一个包再读下一个包,如果异常需要断开重新开始连
				if (_当前内容.addData(this)) {
					_q待处理队列.push(_当前内容);
					_当前内容 = new BIOData1();
				} else {
					break;
				}
			}
		} catch (Exception e) {
			close();
			return;
			// 如果接收过程异常需要重新连接,从错误位置开始重传
			// MyMail.getInstance("zdy1").send("37798955@qq.com", "连接异常", 内容);
		}
	}

	public void close() {
		try {
			if (_srv != null)
				_srv.socketList.remove(this);
			if (_当前连接 != null)
				_当前连接.close();
			_reader.close();
			_reader = null;
			if (curThread != null && curThread.isAlive())
				curThread.interrupt();
			System.out.println("[警告]客户端已经断开");
		} catch (IOException e1) {
		}
	}

	@Override
	/**
	 * 数据包 是 ByteBuffer类型 ,表示包已经打包好了
	 * 数据包 必须是 flip过的 
	 */
	public boolean send(ByteBuffer 数据包) {
		if (_writer == null || 数据包 == null)
			return false;
		try {
			int len=数据包.limit();
			byte[] bb = new byte[len];
			数据包.get(bb);
			_writer.write(bb);
			_writer.flush();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 数据包类型是 byte[] 表示未打包;需要打包
	 */
	public boolean send(byte[] 数据包) {
		return send(IData1.B类型_数据, 数据包);
	}

	/**
	 * 数据包类型是 byte[] 表示未打包;需要打包
	 */

	public boolean send(byte 类型, byte[] 数据包) {
		if (_writer == null || 数据包 == null)
			return false;
		try {
			BIOData1 dp = new BIOData1();
			dp.data = 数据包;
			dp.i类型 = 类型;
			// System.err.println(数据包.length);
			// System.err.println(new String(数据包));
			_writer.write(dp.getSendBytes());
			_writer.flush();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	public BIOData1 pull() {
		return _q待处理队列.pull();
	}

	public byte[] pullData() {
		return _q待处理队列.pull().getData();
	}

	public void pullData(IDo1<byte[]> 回调) {
		while (Thread.currentThread().isAlive()) {
			byte[] data = pullData();
			回调.run(data);
		}
	}

	public void pull(@SuppressWarnings("rawtypes") IDo1<IData1> 回调) {
		while (Thread.currentThread().isAlive()) {
			BIOData1 data = (BIOData1) _q待处理队列.pull();
			回调.run(data);
		}
	}


	public SocketAddress get本地连接() {
		return _当前连接.getLocalSocketAddress();
	}

	public SocketAddress get远程连接() {
		return _当前连接.getRemoteSocketAddress();
	}

}
